package org.noootsab.gae.games.tzaar.service.impl;

import com.google.appengine.api.datastore.*;
import flex.messaging.*;
import flex.messaging.services.*;
import org.noootsab.gae.games.tzaar.model.*;
import org.noootsab.gae.games.tzaar.service.GameService;
import org.noootsab.gae.games.tzaar.service.PersistenceManagerFactoryHelper;

import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.jdo.annotations.Transactional;
import java.util.*;

/**
 * User: sandy
 * Date: 22-mars-2010
 * Time: 22:43:03
 */
public class GameServiceImpl implements GameService {
    @Transactional
    public List<Game> getAllGamesFor(Player player) {
        PersistenceManager persistenceManager = PersistenceManagerFactoryHelper.get().getPersistenceManager();
        List<Game> games = null;
        try {
            Query query = null;
            String queryString = "players.contains(:searchKey) && finished == false";
            query = persistenceManager.newQuery(Game.class, queryString);
            query.setRange(0, 5);
            games = (List<Game>) query.execute(player.getKey());
            //FIXME ... this is a crappy init
            games.size();
            return games;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            persistenceManager.close();
        }
        return games;
    }

    @Transactional
    public List<Game> getAllAccessibleGamesFor(Player player) {
        PersistenceManager persistenceManager = PersistenceManagerFactoryHelper.get().getPersistenceManager();
        List<Game> games = null;
        try {
            Query query = null;
            query = persistenceManager.newQuery(Game.class, "started == false && finished == false");
            query.setRange(0, 5);
            games = (List<Game>) query.execute();
            List<Game> tbrGames = new ArrayList<Game>();
            for (Game game : games) {
                if (game.getPlayers() != null && game.getPlayers().size() >= 0 && game.getPlayers().size() < 2 && game.getPlayers().contains(player.getKey())) {
                    tbrGames.add(game);
                }
            }
            games.removeAll(tbrGames);
            return games;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            persistenceManager.close();
        }
        return games;
    }

    public Game getGameByKey(String key) {
        Key k = KeyFactory.stringToKey(key);
        PersistenceManager persistenceManager = PersistenceManagerFactoryHelper.get().getPersistenceManager();
        Game game = null;
        try {
            game = persistenceManager.getObjectById(Game.class, k);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            persistenceManager.close();
        }
        return game;
    }

    public Game getGameById(String id) {
        PersistenceManager persistenceManager = PersistenceManagerFactoryHelper.get().getPersistenceManager();
        try {
            Query query = persistenceManager.newQuery(Game.class, "gameId==:id");
            query.setUnique(true);
            return (Game) query.execute(id);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            persistenceManager.close();
        }
        return null;
    }

    @Transactional
    public Game createGame(Game game, Player creator) {
        PersistenceManager persistenceManager = PersistenceManagerFactoryHelper.get().getPersistenceManager();
        try {
            game.setGameId(UUID.randomUUID().toString());
            if (game.getPlayers() != null && !game.getPlayers().isEmpty()) {
                if (game.getPlayers().get(0) == null) {
                    game.getPlayers().set(0, creator.getKey());
                } else if (game.getPlayers().size() > 1 && game.getPlayers().get(1) == null) {
                    game.getPlayers().set(1, creator.getKey());
                } else {
                    //todo
                }
            } else {
                List<Key> players = new ArrayList<Key>();
                if (creator != null) {
                    players.add(creator.getKey());
                }
                game.setPlayers(players);
            }
            game = persistenceManager.makePersistent(game);
            return game;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            persistenceManager.close();
        }
        return game;
    }

    public void update(Game game) {
        PersistenceManager persistenceManager = PersistenceManagerFactoryHelper.get().getPersistenceManager();
        try {
            persistenceManager.makePersistent(game);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            persistenceManager.close();
        }
    }

    public void endGame(Game game, Boolean black) {
        if (game.isWinnerBlack() != null) {
            throw new RuntimeException("This game has already ended!");
        }

        PersistenceManager persistenceManager = PersistenceManagerFactoryHelper.get().getPersistenceManager();

        try {
            //persist game in transaction
            persistenceManager.currentTransaction().begin();
            game.setWinnerBlack(black);
            persistenceManager.makePersistent(game);
            persistenceManager.currentTransaction().commit();

            //persist stats in differents transactions
            Key winner = game.getPlayers().get(black ? 1 : 0);
            Key loser = game.getPlayers().get(black ? 0 : 1);

            Query query = persistenceManager.newQuery(Statistic.class, "player == :p");
            query.setUnique(true);

            //update winner stats
            persistenceManager.currentTransaction().begin();
            Statistic winnerStat = (Statistic) query.execute(winner);
            if (winnerStat == null) {
                winnerStat = new Statistic();
                winnerStat.setPlayer(winner);
                persistenceManager.makePersistent(winnerStat);
            }
            winnerStat.wonAgainst(loser);
            persistenceManager.currentTransaction().commit();

            //update loser stats
            persistenceManager.currentTransaction().begin();
            Statistic loserStat = (Statistic) query.execute(loser);
            if (loserStat == null) {
                loserStat = new Statistic();
                loserStat.setPlayer(loser);
                persistenceManager.makePersistent(loserStat);
            }
            loserStat.lostAgainst(winner);
            persistenceManager.currentTransaction().commit();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            persistenceManager.close();
        }
    }
}
